#ifndef ___fat32_transaccionA6_cambiar_nombre

#define ___fat32_transaccionA6_cambiar_nombre 1

#include "f32_mto.c"

#include "f32_st01.c"
#include "f32_st02.c"
#include "f32_st03.c"
#include "f32_st09.c"
#include "f32_st10.c"
#include "f32_st11.c"
#include "f32_st12.c"
#include "f32_st13.c"
#include "f32_st14.c"
#include "f32_st21.c"

enum fat32trA6_errores {
  FAT32_A6_ARCHIVO_ANTERIOR_NO_EXISTE = 1,
  FAT32_A6_ARCHIVO_NUEVO_YA_EXISTE = 2,
  FAT32_A6_DISCO_LLENO = 3,
  FAT32_A6_RUTA_PARA_ARCHIVO_NUEVO_NO_EXISTE = 4
};

struct fat32trA6_datos_entrada {
  char * nombre1;
  char * nombre2;
  unsigned int remitente;
};

struct fat32trA6_datos_internos {
  char * nombre1;
  char * nombre2;
  unsigned int remitenteMensaje;
  signed short errorDevuelto;
  unsigned int conexion;
  char ** ruta1;
  char ** ruta2;
  char ** rutaPadre2;
  char * nombreNuevo;
  char mismoDirectorio;
  unsigned long long descriptor1;
  unsigned long long descriptorPadre2;
  struct fat32_ref_entrada_directorio entrada;
  struct fat32_ref_entrada_directorio entrada2;
  struct fat32_atributos_archivo atributos;
  struct fat32_atributos_archivo atributos2;
  fat32_lista_bloques_para_escribir * lbpe1;
  fat32_lista_bloques_para_escribir * lbpe2;
  fat32_lista_bloques_para_escribir * lbpe3;
  fat32_lista_bloques_para_escribir * lbpeF;
  unsigned long bloqueEntradaNueva;
  unsigned short posicionEntradaNueva;
  void * datosInternos;
};

void fat32tr_cambiar_nombre(char *, char *, unsigned int);
int fat32ctr_cambiar_nombre(FAT32_PARAMS_CREACION_TRANSACCION);
int fat32etr_cambiar_nombre(FAT32_PARAMS_TRANSACCION);

void fat32tr_cambiar_nombre (char * nombreAnterior, char * nombreNuevo, unsigned int remitente) {
  struct fat32trA6_datos_entrada datos;
  datos.remitente = remitente;
  datos.nombre1 = malloc(strlen(nombreAnterior) + 1);
  datos.nombre2 = malloc(strlen(nombreNuevo) + 1);
  memcpy(datos.nombre1, nombreAnterior, strlen(nombreAnterior) + 1);
  memcpy(datos.nombre2, nombreNuevo, strlen(nombreNuevo) + 1);
  fat32_crear_transaccion(&fat32ctr_cambiar_nombre, &datos, sizeof datos);
}

int fat32ctr_cambiar_nombre (FAT32_PARAMS_CREACION_TRANSACCION) {
  struct fat32trA6_datos_entrada * de = datosIniciales;
  struct fat32trA6_datos_internos * di = malloc(sizeof(struct fat32trA6_datos_internos));
  di -> nombre1 = de -> nombre1;
  di -> nombre2 = de -> nombre2;
  di -> remitenteMensaje = de -> remitente;
  *datos = di;
  *handler = &fat32etr_cambiar_nombre;
  return 0xE100;
}

int fat32etr_cambiar_nombre (FAT32_PARAMS_TRANSACCION) {
  unsigned char estado1;
  int estado2;
  estado2 = estado >> 8;
  estado1 = estado & 255;
  struct fat32trA6_datos_internos * datosT = *datos;
  switch (estado2) {
  case 0x01:
    estado1 = fat32st_obtener_conexion(estado1, numeroTransaccion, &(datosT -> conexion), resultadoOperacion, datosOperacion);
    if (!estado1) estado2 = 0x02;
    break;
  case 0x02:
    estado1 = fat32st_ubicar_entrada_directorio(estado1, numeroTransaccion, datosT -> ruta2, &(datosT -> datosInternos), resultadoOperacion,
                                                                                                                             datosOperacion);
    if (!estado1) {
      datosT -> entrada = *((struct fat32_ref_entrada_directorio *) (datosT -> datosInternos));
      free(datosT -> datosInternos);
      estado2 = 0xE1;
      estado1 = 1;
    }
    break;
  case 0x03:
    estado1 = fat32st_ubicar_entrada_directorio(estado1, numeroTransaccion, datosT -> ruta1, &(datosT -> datosInternos), resultadoOperacion,
                                                                                                                             datosOperacion);
    if (!estado1) {
      datosT -> entrada = *((struct fat32_ref_entrada_directorio *) (datosT -> datosInternos));
      free(datosT -> datosInternos);
      estado2 = 0xE1;
      estado1 = 2;
    }
    break;
  case 0x04:
    estado1 = fat32st_ubicar_entrada_directorio(estado1, numeroTransaccion, datosT -> rutaPadre2, &(datosT -> datosInternos),
                                                                                          resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> entrada2 = *((struct fat32_ref_entrada_directorio *) (datosT -> datosInternos));
      free(datosT -> datosInternos);
      estado2 = 0x05;
    }
    break;
  case 0x05:
    estado1 = fat32st_bloquear_directorio_por_escritura_entrada(estado1, numeroTransaccion, datosT -> descriptorPadre2, resultadoOperacion);
    if (!estado1) estado2 = 0x06;
    break;
  case 0x06:
    estado1 = fat32st_bloquear_archivo_totalmente(estado1, numeroTransaccion, datosT -> descriptor1, resultadoOperacion);
    if (!estado1) estado2 = 0x07;
    break;
  case 0x07:
    estado1 = fat32st_obtener_atributos(estado1, numeroTransaccion, (datosT -> entrada).clusterInicial, (datosT -> entrada).posicionEntrada,
                                                                             &(datosT -> datosInternos), resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> atributos = *((struct fat32_atributos_archivo *) (datosT -> datosInternos));
      free(datosT -> datosInternos);
      estado2 = 0x08;
    }
    break;
  case 0x08:
    estado1 = fat32st_obtener_atributos(estado1, numeroTransaccion, (datosT -> entrada2).clusterInicial, (datosT -> entrada2).posicionEntrada,
                                                                               &(datosT -> datosInternos), resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> atributos2 = *((struct fat32_atributos_archivo *) (datosT -> datosInternos));
      free(datosT -> datosInternos);
      estado2 = 0x09;
    }
    break;
  case 0x09:
    estado1 = fat32st_crear_entrada_para_archivo(estado1, numeroTransaccion, datosT -> nombreNuevo, 0, (datosT -> atributos2).clusterInicial,
                                                                              &(datosT -> datosInternos), resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> lbpe1 = ((struct fat32st14_resultado *) (datosT -> datosInternos)) -> lbpe;
      datosT -> bloqueEntradaNueva = ((struct fat32st14_resultado *) (datosT -> datosInternos)) -> numeroBloque;
      datosT -> posicionEntradaNueva = ((struct fat32st14_resultado *) (datosT -> datosInternos)) -> posicionBloque;
      free(datosT -> datosInternos);
      estado2 = 0xE1;
      estado1 = 3;
    }
    break;
  case 0x10:
    estado1 = fat32st_eliminar_entradas_de_directorio_sin_desvincular(estado1, numeroTransaccion, (datosT -> entrada).clusterInicial,
                                                                      (datosT -> entrada).posicionEntrada, &(datosT -> datosInternos),
                                                                      resultadoOperacion, datosOperacion);
    if (!estado1) {
      datosT -> lbpe3 = datosT -> datosInternos;
      estado2 = 0xE1;
      estado1 = 5;
    }
    break;
  case 0x11:
    estado1 = fat32st_ejecutar_lista_bloques_para_escribir(estado1, numeroTransaccion, datosT -> lbpeF, &(datosT -> datosInternos),
                                                                                                resultadoOperacion, datosOperacion);
    if (!estado1) estado2 = 0x12;
    break;
  case 0x12:
    estado1 = fat32st_liberar_bloqueo(estado1, numeroTransaccion, datosT -> descriptor1);
    if (!estado1) estado2 = 0x13;
    break;
  case 0x13:
    estado1 = fat32st_liberar_bloqueo(estado1, numeroTransaccion, datosT -> descriptorPadre2);
    if (!estado1) {
      estado2 = 0xE1;
      estado1 = 6;
    }
    break;
  case 0x14:
    estado1 = fat32st_liberar_conexion(estado1, numeroTransaccion);
    if (!estado1) {
      estado2 = 0xE1;
      estado1 = 7;
    }
    break;
  case 0xE1:
    switch (estado1) {
    case 0:
      datosT -> ruta1 = fat32_obtener_ruta(datosT -> nombre1);
      datosT -> ruta2 = fat32_obtener_ruta(datosT -> nombre2);
      unsigned int posicionRuta;
      datosT -> rutaPadre2 = fat32_copiar_ruta(datosT -> ruta2);
      for (posicionRuta = 0; (datosT -> rutaPadre2)[posicionRuta]; posicionRuta ++);
      posicionRuta --;
      datosT -> nombreNuevo = (datosT -> rutaPadre2)[posicionRuta];
      (datosT -> rutaPadre2)[posicionRuta] = NULL;
      datosT -> mismoDirectorio = fat32_comparar_rutas(datosT -> rutaPadre1, datosT -> rutaPadre2) == FAT32_RUTAS_COINCIDEN;
      datosT -> descriptor1 = fat32_generar_descriptor(datosT -> ruta1, 0);
      if (mismoDirectorio)
        free(datosT -> rutaPadre2);
      else
        datosT -> descriptorPadre2 = fat32_generar_descriptor(datosT -> rutaPadre2, 1);
      datosT -> errorDevuelto = -1;
      datosT -> lbpe1 = NULL;
      datosT -> lbpe2 = NULL;
      datosT -> lbpe3 = NULL;
      datosT -> lbpeF = NULL;
      estado2 = 0x01;
      break;
    case 1:
      if ((datosT -> entrada).resultado == 2) datosT -> errorDevuelto = FAT32_A6_RUTA_PARA_ARCHIVO_NUEVO_NO_EXISTE;
      if (!(datosT -> entrada).resultado) datosT -> errorDevuelto = FAT32_A6_ARCHIVO_NUEVO_YA_EXISTE;
      if (datosT -> entrada).resultado == 1) {
        estado2 = 0x03;
        estado1 = 0;
      } else
        estado1 = 6;
      break;
    case 2:
      if ((datosT -> entrada).resultado) {
        datosT -> errorDevuelto = FAT32_A6_ARCHIVO_ANTERIOR_NO_EXISTE;
        estado1 = 6;
      } else {
        estado2 = 0x04;
        estado1 = 0;
      }
      break;
    case 3:
      if (!(datosT -> lbpe1)) {
        datosT -> errorDevuelto = FAT32_A6_DISCO_LLENO;
        estado1 = 6;
      } else
        estado1 = 4;
      break;
    case 4:
      datosT -> lbpe2 = malloc(sizeof(fat32_lista_bloques_para_escribir));
      fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_CREAR, datosT -> lbpe2, 0, 0, 0, NULL);
      char datosTemp[4];
      fb_convertir_de_little_endian(datosTemp, (datosT -> atributos).clusterInicial, 32);
      fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, datosT -> lbpe2, datosT -> bloqueEntradaNueva,
                                                                  datosT -> posicionEntradaNueva + 20, 2, datosTemp + 2);
      fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, datosT -> lbpe2, datosT -> bloqueEntradaNueva,
                                                                      datosT -> posicionEntradaNueva + 26, 2, datosTemp);
      if ((datosT -> atributos).hardlinks == 1) {
        datosTemp[0] = ((datosT -> atributos).soloLectura) ? 1 : 0;
        datosTemp[0] += ((datosT -> atributos).modificado) ? 32 : 0;
        fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, datosT -> lbpe2, datosT -> bloqueEntradaNueva,
                                                                        datosT -> posicionEntradaNueva + 11, 1, datosTemp);
        fb_convertir_de_little_endian(datosTemp, (datosT -> atributos).tamano, 32);
        fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, datosT -> lbpe2, datosT -> bloqueEntradaNueva,
                                                                        datosT -> posicionEntradaNueva + 28, 4, datosTemp);
      } else {
        datosTemp[0] = 16;
        datosTemp[0] += ((datosT -> atributos).soloLectura) ? 1 : 0;
        datosTemp[0] += ((datosT -> atributos).modificado) ? 32 : 0;
        fat32_operar_sobre_lista_bloques_para_escribir(FAT32_LBPE_ESCRIBIR, datosT -> lbpe2, datosT -> bloqueEntradaNueva,
                                                                        datosT -> posicionEntradaNueva + 11, 1, datosTemp);
      }
      estado2 = 0x10;
      estado1 = 0;
      break;
    case 5:
      datosT -> lbpeF = malloc(sizeof(fat32_lista_bloques_para_escribir));
      fat32_combinar_listas_bloques_para_escribir(datosT -> lbpeF, datosT -> lbpe1, datosT -> lbpe2, datosT -> lbpe3, NULL);
      estado2 = 0x11;
      estado1 = 0;
      break;
    case 6:
      if ((datosT -> errorDevuelto) == -1)
        mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_ARCHIVO_RENOMBRO, datosT -> nombre1, datosT -> nombre2);
      else
        mtf_enviar_mensaje(fat32_centro_mensajes, datosT -> remitenteMensaje, MTR_ARCHIVO_NO_RENOMBRO, datosT -> nombre1,
                                                                                         (int) (datosT -> errorDevuelto));
      estado2 = 0x14;
      estado1 = 0;
      break;
    case 7:
      fat32_destruir_ruta(datosT -> ruta1);
      fat32_destruir_ruta(datosT -> ruta2);
      fat32_destruir_ruta(datosT -> rutaPadre2);
      fat32_liberar_descriptor(datosT -> descriptor1);
      fat32_liberar_descriptor(datosT -> descriptorPadre2);
      if (datosT -> lbpe1) free(datosT -> lbpe1);
      if (datosT -> lbpe2) free(datosT -> lbpe2);
      if (datosT -> lbpe3) free(datosT -> lbpe3);
      if (datosT -> lbpeF) free(datosT -> lbpeF);
      free(datosT -> nombre1);
      free(datosT -> nombre2);
      free(datosT -> nombreNuevo);
      free(datosT);
      estado1 = 0;
      estado2 = 0;
    }
    break;
  }
  return (estado2 << 8) | estado1;
}

#endif